Skip to content

Commit

Permalink
4500: Konverterer til PDF
Browse files Browse the repository at this point in the history
  • Loading branch information
thanglyphan committed Nov 29, 2023
1 parent 450845c commit 6657ebb
Show file tree
Hide file tree
Showing 8 changed files with 253 additions and 53 deletions.
8 changes: 8 additions & 0 deletions melosys-eessi-app/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@


<dependencies>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.poi.xwpf.converter.pdf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package no.nav.melosys.eessi.integration.eux.rina_api;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;

import com.fasterxml.jackson.core.JsonProcessingException;
Expand All @@ -15,6 +17,9 @@
import no.nav.melosys.eessi.models.exception.NotFoundException;
import no.nav.melosys.eessi.models.sed.SED;
import no.nav.melosys.eessi.models.vedlegg.SedMedVedlegg;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.io.ByteArrayResource;
Expand Down Expand Up @@ -147,20 +152,56 @@ public void sendSed(String rinaSaksnummer, String dokumentId) {
rinaSaksnummer, dokumentId);
}

public String leggTilVedlegg(String rinaSaksnummer, String dokumentId, String filType,

private boolean skalKonvertereTilPDF(String filType) {
return Arrays.asList(".doc", ".docx", ".jpg", ".jpeg", ".TIF", ".TIFF").contains(filType.toLowerCase());
}

public String leggTilVedlegg(String rinaSaksnummer, String dokumentId, String filtype,
SedVedlegg vedlegg) {
log.info("Legger til vedlegg på sak {} og dokument {}", rinaSaksnummer, dokumentId);

if (skalKonvertereTilPDF(filtype)) {
log.info("KonverterTilPDF: Konverterer vedlegget til PDF fra {}, dokument {}", filtype, dokumentId);
byte[] pdfContent = konverterToPDF(vedlegg.getInnhold(), filtype);
vedlegg = new SedVedlegg(vedlegg.getTittel(), pdfContent);
filtype = "pdf";
} else {
log.info("KonverterTilPDF: Konverterer ikke, {}", filtype);
}

var headers = defaultHeaders();
String base64Content = Base64.getEncoder().encodeToString(vedlegg.getInnhold());
var body = new EuxVedlegg(base64Content, filType, vedlegg.getTittel(), true);
var body = new EuxVedlegg(base64Content, filtype, vedlegg.getTittel(), true);

return exchange(VEDLEGG_PATH, HttpMethod.POST,
new HttpEntity<>(body, headers),
new ParameterizedTypeReference<>() {},
rinaSaksnummer, dokumentId);
}


private byte[] konverterToPDF(byte[] content, String filtype) {
try (PDDocument document = new PDDocument()) {
log.info("KonverterTilPDF: Prøver å converte filtype: {}", filtype);

PDPage page = new PDPage();
document.addPage(page);

try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
contentStream.showText(new String(content));
}

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
document.save(outputStream);
document.close();

return outputStream.toByteArray();
} catch (IOException e) {
log.info("KonverterTilPDF feiler: {}", e.getMessage());
throw new RuntimeException(e);
}
}
public void setSakSensitiv(String rinaSaksnummer) {
log.info("Setter sak {} sensitiv", rinaSaksnummer);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@

// https://confluence.adeo.no/display/BOA/Filtype
public enum JournalpostFiltype {
PDF,
PDFA,
XML,
RTF,
DLF,
JPEG,
TIFF,
AXML,
DXML,
JSON,
PNG;
PDF,
PDFA,
XML,
RTF,
DLF,
JPEG,
TIFF,
AXML,
DXML,
JSON,
DOCX,
PNG;

private static final Map<String, JournalpostFiltype> FILENDELSE_FILTYPE_MAP = Arrays.stream(JournalpostFiltype.values())
.collect(Collectors.toMap(JournalpostFiltype::name, v -> v));
Expand All @@ -31,22 +32,37 @@ public enum JournalpostFiltype {
.put("image/png", PNG)
.build();

private static final Map<String, JournalpostFiltype> MIMETYPE_FILTYPE_MAP_NY = ImmutableMap.<String, JournalpostFiltype>builder()
.put("application/pdf", PDF)
.put("image/jpg", JPEG)
.put("image/jpeg", JPEG)
.put("image/png", PNG)
.put("image/tiff", TIFF)
.put("application/vnd.openxmlformats-officedocument.wordprocessing", DOCX)
.put("application/vnd.openxmlformats-officedocument.wordprocessingml.document", DOCX)
.build();

public static Optional<JournalpostFiltype> fraMimeOgFilnavn(String mimeType, String filnavn) {
if (MIMETYPE_FILTYPE_MAP.containsKey(mimeType)) {
return Optional.of(MIMETYPE_FILTYPE_MAP.get(mimeType));
}

return Optional.ofNullable(filnavn)
.filter(s -> s.contains(".") && s.lastIndexOf('.') + 1 < s.length())
.map(s -> s.substring(s.lastIndexOf('.') + 1))
.map(String::toUpperCase)
.map(JournalpostFiltype::transform)
.filter(JournalpostFiltype::contains)
.map(JournalpostFiltype::valueOf);

public static Optional<JournalpostFiltype> fraMimeOgFilnavn(String mimeType, String filnavn, Boolean skalKonvertereTilPDF ) {
if (skalKonvertereTilPDF && MIMETYPE_FILTYPE_MAP_NY.containsKey(mimeType)) {
return Optional.of(MIMETYPE_FILTYPE_MAP_NY.get(mimeType));
}

if (MIMETYPE_FILTYPE_MAP.containsKey(mimeType)) {
return Optional.of(MIMETYPE_FILTYPE_MAP.get(mimeType));
}

return Optional.ofNullable(filnavn)
.filter(s -> s.contains(".") && s.lastIndexOf('.') + 1 < s.length())
.map(s -> s.substring(s.lastIndexOf('.') + 1))
.map(String::toUpperCase)
.map(JournalpostFiltype::transform)
.filter(JournalpostFiltype::contains)
.map(JournalpostFiltype::valueOf);
}

public static boolean erGyldigFiltypeForVariantformatArkiv(JournalpostFiltype journalpostFiltype) {
public static boolean erGyldigFiltypeForVariantformatArkiv(JournalpostFiltype journalpostFiltype) {
return journalpostFiltype == PDF || journalpostFiltype == PDFA;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,65 @@
package no.nav.melosys.eessi.integration.journalpostapi;

import fr.opensagres.poi.xwpf.converter.pdf.PdfConverter;
import fr.opensagres.poi.xwpf.converter.pdf.PdfOptions;
import io.getunleash.Unleash;
import lombok.extern.slf4j.Slf4j;
import no.nav.melosys.eessi.integration.sak.Sak;
import no.nav.melosys.eessi.kafka.consumers.SedHendelse;
import no.nav.melosys.eessi.models.exception.MappingException;
import no.nav.melosys.eessi.models.vedlegg.SedMedVedlegg;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.image.JPEGFactory;
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.poi.openxml4j.util.ZipSecureFile;
import org.apache.poi.xwpf.usermodel.XWPFDocument;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static no.nav.melosys.eessi.integration.journalpostapi.JournalpostFiltype.*;
import static no.nav.melosys.eessi.integration.journalpostapi.OpprettJournalpostRequest.*;
import static no.nav.melosys.eessi.service.sed.SedTypeTilTemaMapper.temaForSedType;
import static org.apache.commons.lang3.StringUtils.isEmpty;
import static org.apache.commons.lang3.StringUtils.isNotEmpty;

@Slf4j
public final class OpprettJournalpostRequestMapper {

private OpprettJournalpostRequestMapper() {
}
public static final double MIN_INFLATE_RATIO = 0.001;
public static final float PDF_MARGIN = 20.0f;

public static OpprettJournalpostRequest opprettInngaaendeJournalpost(final SedHendelse sedHendelse,
final SedMedVedlegg sedMedVedlegg,
final Sak sak,
final String dokumentTittel,
final String behandlingstema,
final String personIdent) {
return opprettJournalpostRequest(JournalpostType.INNGAAENDE, sedHendelse, sedMedVedlegg, sak, dokumentTittel, behandlingstema, personIdent);
final String personIdent,
final Boolean skalKonvertereTilPDF) {
return opprettJournalpostRequest(JournalpostType.INNGAAENDE, sedHendelse, sedMedVedlegg, sak, dokumentTittel, behandlingstema, personIdent, skalKonvertereTilPDF);
}

public static OpprettJournalpostRequest opprettUtgaaendeJournalpost(final SedHendelse sedHendelse,
final SedMedVedlegg sedMedVedlegg,
final Sak sak,
final String dokumentTittel,
final String behandlingstema,
final String personIdent) {
return opprettJournalpostRequest(JournalpostType.UTGAAENDE, sedHendelse, sedMedVedlegg, sak, dokumentTittel, behandlingstema, personIdent);
final String personIdent,
final Boolean skalKonvertereTilPDF) {
return opprettJournalpostRequest(JournalpostType.UTGAAENDE, sedHendelse, sedMedVedlegg, sak, dokumentTittel, behandlingstema, personIdent, skalKonvertereTilPDF);
}


Expand All @@ -49,13 +69,14 @@ private static OpprettJournalpostRequest opprettJournalpostRequest(final Journal
final Sak sak,
final String dokumentTittel,
final String behandlingstema,
final String personIdent) {
final String personIdent,
final Boolean skalKonvertereTilPDF) {

return OpprettJournalpostRequest.builder()
.avsenderMottaker(getAvsenderMottaker(journalpostType, sedHendelse))
.behandlingstema(behandlingstema)
.bruker(isNotEmpty(personIdent) ? lagBruker(personIdent) : null)
.dokumenter(dokumenter(sedHendelse.getSedType(), sedMedVedlegg, dokumentTittel))
.dokumenter(dokumenter(sedHendelse.getSedType(), sedMedVedlegg, dokumentTittel, skalKonvertereTilPDF))
.eksternReferanseId(sedHendelse.getSedId())
.journalfoerendeEnhet("4530")
.journalpostType(journalpostType)
Expand Down Expand Up @@ -88,11 +109,12 @@ private static AvsenderMottaker getAvsenderMottaker(final JournalpostType type,

private static List<Dokument> dokumenter(final String sedType,
final SedMedVedlegg sedMedVedlegg,
final String dokumentTittel) {
final String dokumentTittel,
final Boolean skalKonvertereTilPDF) {
final List<Dokument> dokumenter = new ArrayList<>();

dokumenter.add(dokument(sedType, dokumentTittel, JournalpostFiltype.PDFA, sedMedVedlegg.getSed().getInnhold()));
dokumenter.addAll(vedlegg(sedType, sedMedVedlegg.getVedleggListe()));
dokumenter.addAll(vedlegg(sedType, sedMedVedlegg.getVedleggListe(), skalKonvertereTilPDF));
return dokumenter;
}

Expand All @@ -112,16 +134,20 @@ private static Dokument dokument(final String sedType,
}

private static List<Dokument> vedlegg(final String sedType,
final List<SedMedVedlegg.BinaerFil> vedleggListe) {
final List<SedMedVedlegg.BinaerFil> vedleggListe,
final Boolean skalKonvertereTilPDF) {

log.info("KonverteringPDF: toggle er {}", skalKonvertereTilPDF);
return vedleggListe.stream()
.filter(gyldigFiltypePredicate)
.map(binærfil ->
dokument(sedType,
.map(binærfil -> {
JournalpostFiltype opprinneligFiltype = JournalpostFiltype.fraMimeOgFilnavn(binærfil.getMimeType(), binærfil.getFilnavn(), skalKonvertereTilPDF).orElseThrow(() -> new MappingException("Filtype kreves for "
+ binærfil.getFilnavn() + " (" + binærfil.getMimeType() + ")"));

return dokument(sedType,
isEmpty(binærfil.getFilnavn()) ? "Vedlegg" : binærfil.getFilnavn(),
JournalpostFiltype.fraMimeOgFilnavn(binærfil.getMimeType(), binærfil.getFilnavn())
.orElseThrow(() -> new MappingException("Filtype kreves for "
+ binærfil.getFilnavn() + " (" + binærfil.getMimeType() + ")")),
binærfil.getInnhold())
skalKonvertereTilPDF ? PDF : opprinneligFiltype,
skalKonvertereTilPDF ? getPdfByteArray(binærfil, opprinneligFiltype) : binærfil.getInnhold());
}
)
.collect(Collectors.toList());
}
Expand All @@ -137,7 +163,7 @@ private static String temaForSedTypeOgJournalpostType(final String sedType,
}

private static final Predicate<SedMedVedlegg.BinaerFil> gyldigFiltypePredicate = binaerFil -> {
final boolean gyldigFiltype = JournalpostFiltype.fraMimeOgFilnavn(binaerFil.getMimeType(), binaerFil.getFilnavn())
final boolean gyldigFiltype = JournalpostFiltype.fraMimeOgFilnavn(binaerFil.getMimeType(), binaerFil.getFilnavn(), false)
.map(JournalpostFiltype::erGyldigFiltypeForVariantformatArkiv)
.orElse(Boolean.FALSE);

Expand All @@ -147,4 +173,76 @@ private static String temaForSedTypeOgJournalpostType(final String sedType,
}
return gyldigFiltype;
};

private static byte[] getPdfByteArray(SedMedVedlegg.BinaerFil binaerFil, JournalpostFiltype filtype) {
log.info("KonverteringPDF: Konverter fra {} til PDF", filtype);
switch (filtype) {
case PDF: {
return binaerFil.getInnhold();
}
case DOCX: {
return convertWordToPdf(binaerFil, filtype).toByteArray();
}
case TIFF:
case JPEG: {
return convertImageToPdf(binaerFil, filtype).toByteArray();
}
default:
throw new RuntimeException("Mangler logikk for vedleggstype " + filtype);
}
}

private static ByteArrayOutputStream convertWordToPdf(SedMedVedlegg.BinaerFil binaerFil, JournalpostFiltype konverterbarFiltype) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
log.info("KonverteringPDF: Konverterer start convertWordToPdf");
try {
InputStream is = new ByteArrayInputStream(binaerFil.getInnhold());
log.info("KonverteringPDF: inputstream ferdig");

if (konverterbarFiltype == JournalpostFiltype.DOCX) {
ZipSecureFile.setMinInflateRatio(MIN_INFLATE_RATIO);
XWPFDocument document = new XWPFDocument(is);
PdfOptions options = PdfOptions.create();
PdfConverter.getInstance().convert(document, out, options);
log.info("KonverteringPDF: convert ferdig");
} else {
throw new IllegalArgumentException("KonverteringPDF: Ikke implementert støtte for konvertering av filtype " + konverterbarFiltype);
}
} catch (IOException | StackOverflowError e) { // StackOverflowError kan kastes av PDF-konverteringen, f.eks. ved uendelig forsøk på tekstbryting
throw new RuntimeException("KonverteringPDF: Kunne ikke konvertere vedlegg " + binaerFil.getFilnavn() +
" med MIME-type " + binaerFil.getMimeType() + " til PDF", e);
}
log.info("KonverteringPDF: out er {}", out);

return out;
}


private static ByteArrayOutputStream convertImageToPdf(SedMedVedlegg.BinaerFil binaerFil, JournalpostFiltype filtype) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (PDDocument doc = new PDDocument()) {
InputStream in = new ByteArrayInputStream(binaerFil.getInnhold());
BufferedImage bImageFromConvert = ImageIO.read(in);
PDImageXObject pdImage;
if (filtype == JournalpostFiltype.JPEG) {
pdImage = JPEGFactory.createFromImage(doc, bImageFromConvert);
} else {
pdImage = LosslessFactory.createFromImage(doc, bImageFromConvert);
}

PDRectangle rectangle = new PDRectangle(pdImage.getWidth() + PDF_MARGIN * 2, pdImage.getHeight() + PDF_MARGIN * 2);
PDPage page = new PDPage(rectangle);
doc.addPage(page);

try (PDPageContentStream contents = new PDPageContentStream(doc, page)) {
contents.drawImage(pdImage, PDF_MARGIN, PDF_MARGIN);
}
doc.save(baos);
} catch (IOException e) {
throw new RuntimeException("KonverteringPDF: Kunne ikke konvertere vedlegg " + binaerFil.getFilnavn() +
" med MIME-type " + binaerFil.getMimeType() + " til PDF", e);
}
return baos;
}

}
Loading

0 comments on commit 6657ebb

Please sign in to comment.