mirror of
https://github.com/sismics/docs.git
synced 2025-12-18 04:01:42 +00:00
Closes #77: Metadata in PDF export
This commit is contained in:
@@ -7,6 +7,8 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
@@ -17,6 +19,7 @@ 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.font.PDType1Font;
|
||||
import org.apache.pdfbox.pdmodel.graphics.image.JPEGFactory;
|
||||
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
|
||||
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
||||
@@ -29,8 +32,11 @@ import org.odftoolkit.odfdom.doc.OdfTextDocument;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.io.Closer;
|
||||
import com.sismics.docs.core.dao.jpa.dto.DocumentDto;
|
||||
import com.sismics.docs.core.model.jpa.File;
|
||||
import com.sismics.docs.core.util.pdf.PdfPage;
|
||||
import com.sismics.util.ImageUtil;
|
||||
import com.sismics.util.mime.MimeType;
|
||||
|
||||
@@ -141,21 +147,16 @@ public class PdfUtil {
|
||||
/**
|
||||
* Convert a document and its files to a merged PDF file.
|
||||
*
|
||||
* @param documentDto Document DTO
|
||||
* @param fileList List of files
|
||||
* @param fitImageToPage Fit images to the page
|
||||
* @param metadata Add a page with metadata
|
||||
* @param comment Add a page with comments
|
||||
* @param margin Margins in millimeters
|
||||
* @return PDF input stream
|
||||
* @throws IOException
|
||||
*/
|
||||
public static InputStream convertToPdf(List<File> fileList, boolean fitImageToPage, boolean metadata, boolean comments, int margin) throws Exception {
|
||||
// TODO PDF Export: Option to add a front page with:
|
||||
// document title, document description, creator, date created, language,
|
||||
// additional dublincore metadata (except relations)
|
||||
// list of all files (and information if it is in this document or not)
|
||||
// TODO PDF Export: Option to add the comments
|
||||
|
||||
public static InputStream convertToPdf(DocumentDto documentDto, List<File> fileList,
|
||||
boolean fitImageToPage, boolean metadata, int margin) throws Exception {
|
||||
// Setup PDFBox
|
||||
Closer closer = Closer.create();
|
||||
MemoryUsageSetting memUsageSettings = MemoryUsageSetting.setupMixed(1000000); // 1MB max memory usage
|
||||
@@ -166,12 +167,45 @@ public class PdfUtil {
|
||||
try (PDDocument doc = new PDDocument(memUsageSettings)) {
|
||||
// Add metadata
|
||||
if (metadata) {
|
||||
|
||||
}
|
||||
|
||||
// Add comments
|
||||
if (comments) {
|
||||
|
||||
PDPage page = new PDPage();
|
||||
doc.addPage(page);
|
||||
try (PdfPage pdfPage = new PdfPage(doc, page, margin * mmPerInch, PDType1Font.HELVETICA, 12)) {
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
pdfPage.addText(documentDto.getTitle(), true, PDType1Font.HELVETICA_BOLD, 16)
|
||||
.newLine()
|
||||
.addText("Created by " + documentDto.getCreator()
|
||||
+ " on " + dateFormat.format(new Date(documentDto.getCreateTimestamp())), true)
|
||||
.newLine()
|
||||
.addText(documentDto.getDescription())
|
||||
.newLine();
|
||||
if (!Strings.isNullOrEmpty(documentDto.getSubject())) {
|
||||
pdfPage.addText("Subject: " + documentDto.getSubject());
|
||||
}
|
||||
if (!Strings.isNullOrEmpty(documentDto.getIdentifier())) {
|
||||
pdfPage.addText("Identifier: " + documentDto.getIdentifier());
|
||||
}
|
||||
if (!Strings.isNullOrEmpty(documentDto.getPublisher())) {
|
||||
pdfPage.addText("Publisher: " + documentDto.getPublisher());
|
||||
}
|
||||
if (!Strings.isNullOrEmpty(documentDto.getFormat())) {
|
||||
pdfPage.addText("Format: " + documentDto.getFormat());
|
||||
}
|
||||
if (!Strings.isNullOrEmpty(documentDto.getSource())) {
|
||||
pdfPage.addText("Source: " + documentDto.getSource());
|
||||
}
|
||||
if (!Strings.isNullOrEmpty(documentDto.getType())) {
|
||||
pdfPage.addText("Type: " + documentDto.getType());
|
||||
}
|
||||
if (!Strings.isNullOrEmpty(documentDto.getCoverage())) {
|
||||
pdfPage.addText("Coverage: " + documentDto.getCoverage());
|
||||
}
|
||||
if (!Strings.isNullOrEmpty(documentDto.getRights())) {
|
||||
pdfPage.addText("Rights: " + documentDto.getRights());
|
||||
}
|
||||
pdfPage.addText("Language: " + documentDto.getLanguage())
|
||||
.newLine()
|
||||
.addText("Files in this document : " + fileList.size(), false, PDType1Font.HELVETICA_BOLD, 12);
|
||||
}
|
||||
}
|
||||
|
||||
// Add files
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
package com.sismics.docs.core.util.pdf;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||
import org.apache.pdfbox.pdmodel.font.PDFont;
|
||||
|
||||
/**
|
||||
* Wrapper around PDFBox for high level abstraction of PDF writing.
|
||||
*
|
||||
* @author bgamard
|
||||
*/
|
||||
public class PdfPage implements Closeable {
|
||||
private PDPage pdPage;
|
||||
private PDPageContentStream pdContent;
|
||||
private float margin;
|
||||
private PDFont defaultFont;
|
||||
private int defaultFontSize;
|
||||
|
||||
/**
|
||||
* Create a wrapper around a PDF page.
|
||||
*
|
||||
* @param pdDoc Document
|
||||
* @param pdPage Page
|
||||
* @param margin Margin
|
||||
* @param defaultFont Default font
|
||||
* @param defaultFontSize Default fond size
|
||||
* @throws IOException
|
||||
*/
|
||||
public PdfPage(PDDocument pdDoc, PDPage pdPage, float margin, PDFont defaultFont, int defaultFontSize) throws IOException {
|
||||
this.pdPage = pdPage;
|
||||
this.pdContent = new PDPageContentStream(pdDoc, pdPage);
|
||||
this.margin = margin;
|
||||
this.defaultFont = defaultFont;
|
||||
this.defaultFontSize = defaultFontSize;
|
||||
|
||||
pdContent.beginText();
|
||||
pdContent.newLineAtOffset(margin, pdPage.getMediaBox().getHeight() - margin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a text with default font.
|
||||
*
|
||||
* @param text Text
|
||||
* @throws IOException
|
||||
*/
|
||||
public PdfPage addText(String text) throws IOException {
|
||||
drawText(pdPage.getMediaBox().getWidth() - 2 * margin, defaultFont, defaultFontSize, text, false);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a text with default font.
|
||||
*
|
||||
* @param text Text
|
||||
* @param centered If true, the text will be centered in the page
|
||||
* @throws IOException
|
||||
*/
|
||||
public PdfPage addText(String text, boolean centered) throws IOException {
|
||||
drawText(pdPage.getMediaBox().getWidth() - 2 * margin, defaultFont, defaultFontSize, text, centered);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a text in the page.
|
||||
*
|
||||
* @param text Text
|
||||
* @param centered If true, the text will be centered in the page
|
||||
* @param font Font
|
||||
* @param fontSize Font size
|
||||
* @throws IOException
|
||||
*/
|
||||
public PdfPage addText(String text, boolean centered, PDFont font, int fontSize) throws IOException {
|
||||
drawText(pdPage.getMediaBox().getWidth() - 2 * margin, font, fontSize, text, centered);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new line.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public PdfPage newLine() throws IOException {
|
||||
pdContent.newLineAtOffset(0, - defaultFont.getFontDescriptor().getFontBoundingBox().getHeight() / 1000 * defaultFontSize);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a text with low level PDFBox API.
|
||||
*
|
||||
* @param paragraphWidth Paragraph width
|
||||
* @param font Font
|
||||
* @param fontSize Font size
|
||||
* @param text Text
|
||||
* @param centered If true, the text will be centered in the paragraph
|
||||
* @throws IOException
|
||||
*/
|
||||
private void drawText(float paragraphWidth, PDFont font, int fontSize, String text, boolean centered) throws IOException {
|
||||
pdContent.setFont(font, fontSize);
|
||||
int start = 0;
|
||||
int end = 0;
|
||||
float height = font.getFontDescriptor().getFontBoundingBox().getHeight() / 1000 * fontSize;
|
||||
for (int i : possibleWrapPoints(text)) {
|
||||
float width = font.getStringWidth(text.substring(start, i)) / 1000 * fontSize;
|
||||
if (start < end && width > paragraphWidth) {
|
||||
// Draw partial text and increase height
|
||||
pdContent.newLineAtOffset(0, - height);
|
||||
String line = text.substring(start, end);
|
||||
float lineWidth = font.getStringWidth(line) / 1000 * fontSize;
|
||||
float offset = (paragraphWidth - lineWidth) / 2;
|
||||
if (centered) pdContent.newLineAtOffset(offset, 0);
|
||||
pdContent.showText(line);
|
||||
if (centered) pdContent.newLineAtOffset(- offset, 0);
|
||||
start = end;
|
||||
}
|
||||
end = i;
|
||||
}
|
||||
|
||||
// Last piece of text
|
||||
String line = text.substring(start);
|
||||
float lineWidth = font.getStringWidth(line) / 1000 * fontSize;
|
||||
float offset = (paragraphWidth - lineWidth) / 2;
|
||||
pdContent.newLineAtOffset(0, - height);
|
||||
if (centered) pdContent.newLineAtOffset(offset, 0);
|
||||
pdContent.showText(line);
|
||||
if (centered) pdContent.newLineAtOffset(- offset, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns wrap points for a given piece of text.
|
||||
*
|
||||
* @param text Text
|
||||
* @return Wrap points
|
||||
*/
|
||||
private int[] possibleWrapPoints(String text) {
|
||||
String[] split = text.split("(?<=\\W)");
|
||||
int[] ret = new int[split.length];
|
||||
ret[0] = split[0].length();
|
||||
for (int i = 1 ; i < split.length ; i++) {
|
||||
ret[i] = ret[i-1] + split[i].length();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
pdContent.endText();
|
||||
pdContent.close();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user