1
0
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:
jendib
2016-03-15 00:43:27 +01:00
parent c2a2e9f585
commit 00ee2d3bf6
4 changed files with 228 additions and 19 deletions

View File

@@ -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

View File

@@ -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();
}
}